/*
 * REFXMLTextReaderImpl.h
 *
 *  Created on: Apr 1, 2013
 *      Author: Lucifer
 */
#ifndef	__BFX_REFXMLTEXTREADERIMPL_H__
#define	__BFX_REFXMLTEXTREADERIMPL_H__

#include "../../pch.h"
#include "../REFXMLReader.h"
#include "XMLLineInfo.h"
#include "../schema/REFXMLSchemaEntity.h"
#include "../schema/REFXMLDtdParser.h"
#include "REFXMLNamespaceManager.h"

namespace BFX
{

//////////////////////////////////////////////////////////////////////////////
class REFXMLTextReader;

class REFXMLTextReaderImpl : public REFXMLReader
{
	friend class REFXMLTextReader;

private:
	//
	// Private helper types
	//
	// ParsingFunction = what should the reader do when the next Read() is called
	enum ParsingFunction
	{
		ParsingFunctionElementContent = 0,
		ParsingFunctionNoData,
		ParsingFunctionOpenUrl,
		ParsingFunctionSwitchToInteractive,
		ParsingFunctionSwitchToInteractiveXmlDecl,
		ParsingFunctionDocumentContent,
		ParsingFunctionMoveToElementContent,
		ParsingFunctionPopElementContext,
		ParsingFunctionPopEmptyElementContext,
		ParsingFunctionResetAttributesRootLevel,
		ParsingFunctionError,
		ParsingFunctionEof,
		ParsingFunctionReaderClosed,
		ParsingFunctionEntityReference,
		ParsingFunctionInIncrementalRead,
		ParsingFunctionFragmentAttribute,
		ParsingFunctionReportEndEntity,
		ParsingFunctionAfterResolveEntityInContent,
		ParsingFunctionAfterResolveEmptyEntityInContent,
		ParsingFunctionXmlDeclarationFragment,
		ParsingFunctionGoToEof,
		ParsingFunctionPartialTextValue,

		// these two states must be last; see InAttributeValueIterator property
		ParsingFunctionInReadAttributeValue,
		ParsingFunctionInReadValueChunk,
		ParsingFunctionInReadContentAsBinary,
		ParsingFunctionInReadElementContentAsBinary,
	};

	enum ParsingMode
	{
		ParsingModeFull,
		ParsingModeSkipNode,
		ParsingModeSkipContent,
	};

	enum EntityType
	{
		EntityTypeError = -1,
		EntityTypeCharacterDec,
		EntityTypeCharacterHex,
		EntityTypeCharacterNamed,
		EntityTypeExpanded,
		EntityTypeExpandedInAttribute,
		EntityTypeSkipped,
		EntityTypeUnexpanded,
		EntityTypeFakeExpanded,
	};

	enum EntityExpandType
	{
		EntityExpandTypeOnlyGeneral,
		EntityExpandTypeOnlyCharacter,
		EntityExpandTypeAll,
	};

	enum IncrementalReadState
	{
		// Following values are used in ReadText, ReadBase64 and ReadBinHex (V1 streaming methods)
		IncrementalReadStateText,
		IncrementalReadStateStartTag,
		IncrementalReadStatePI,
		IncrementalReadStateCDATA,
		IncrementalReadStateComment,
		IncrementalReadStateAttributes,
		IncrementalReadStateAttributeValue,
		IncrementalReadStateReadData,
		IncrementalReadStateEndElement,
		IncrementalReadStateEnd,

		// Following values are used in ReadTextChunk, ReadContentAsBase64 and ReadBinHexChunk (V2 streaming methods)
		IncrementalReadStateReadValueChunk_OnCachedValue,
		IncrementalReadStateReadValueChunk_OnPartialValue,

		IncrementalReadStateReadContentAsBinary_OnCachedValue,
		IncrementalReadStateReadContentAsBinary_OnPartialValue,
		IncrementalReadStateReadContentAsBinary_End,
	};

	// Parsing state (aka. scanner data) - holds parsing buffer and entity input data information
	struct ParsingState: public REFObject
	{
		// character buffer
		UCHAR*	m_pChars;
		int		m_nCharsLength;
		int		m_nCharPos;
		int		m_nCharsUsed;
		// append / rewrite mode switch
		bool	m_bAppendMode;
		// current line number & position
		int		m_nLineNo;
		int		m_nLineStartPos;

		// base uri of the current entity
		UniString	m_strBaseUri;
		// character encoding
		UniString	m_strEncoding;
		// input text reader
		REF<REFUniTextReader>	m_pTextReader;
		// EOF flag of the entity
		bool	m_bIsEof;

		// entity type & id
		REF<REFXMLSchemaEntity>	m_pEntity;
		int		m_nEntityId;

		ParsingState();
		virtual ~ParsingState();
		// Returns the current line position.
		int GetLinePos() const;
	};

	// Node data
	struct NodeData : public REFObject
	{
		// type
		XMLNodeType	m_type;
		// name
		UniString	m_strLocalName;
		UniString	m_strPrefix;
		UniString	m_strNs;
		UniString	m_strNameWPrefix;
		// value
		UniString	m_strValue;
		// main line info
		XMLLineInfo	m_lineInfo;
		// second line info
		XMLLineInfo	m_lineInfo2;
		// quote char for attributes
		UCHAR		m_quoteChar;
		// depth
		int			m_nDepth;
		// empty element / default attribute
		bool		m_bIsEmptyOrDefault;
		// entity id
		int			m_nEntityId;

		// attribute value chunks
		REF<NodeData>	m_pNextAttrValueChunk;


		NodeData();
		int GetLineNo() const;
		int GetLinePos() const;
		void SetLineInfo(int nLineNo, int nLinePos);
		void SetLineInfo2(int nLineNo, int nLinePos);
		void SetValueNode(XMLNodeType type, const UniString& strValue);
		void SetNamedNode(XMLNodeType type, const UniString& strLocalName);
		void SetNamedNode(XMLNodeType type, const UniString& strLocalName, const UniString& strPrefix, const UniString& strNameWPrefix);
		void SetValue(const UniString strValue);
		bool IsEmptyElement() const;
		void SetEmptyElement(bool bIsEmptyElement);
		bool IsDefaultAttribute() const;
		void SetDefaultAttribute(bool bIsDefaultAttribute);
		void CopyTo(REFUniStringBuilder* sb);
		void CopyTo(int nValueOffset, REFUniStringBuilder* sb);
		void Clear(XMLNodeType type);
	};

	// An enumeration for the xml:space scope used in XmlReader and XmlWriter.
	enum XMLSpace
	{
		XMLSpaceNone		= 0,	// xml:space scope has not been specified.
		XMLSpaceDefault		= 1,	// The xml:space scope is "default".
		XMLSpacePreserve	= 2		// The xml:space scope is "preserve".
	};

	//
	// XmlContext
	//
	class XMLContext : public REFObject
	{
		// Constructors
	public:
		XMLContext();
		XMLContext(XMLContext* pPreviousContext);

		// Fields
		XMLSpace		m_xmlSpace;
		UniString		m_strXmlLang;
		UniString		m_strDefaultNamespace;
		REF<XMLContext>	m_pPreviousContext;
	};

	// IDtdParserAdapter proxy for REFXMLTextReader
	class DtdParserProxy : public REFXMLDtdParserAdapter
	{
		// Fields
	private:
		REFXMLTextReaderImpl*	m_pReader;
		REF<REFXMLDtdParser>	m_pDtdParser;

	public:
		// Constructors
		DtdParserProxy(REFXMLTextReaderImpl* pReader);

		// Implementations
		void Parse(bool bSaveInternalSubset);
		REFXMLSchemaInfo* GetDtdSchemaInfo() const;

		UniString GetInternalDtdSubset() const;

		//
		// IDtdParserAdapter proxies
		//
		virtual REFNameTable* GetNameTable() const;
		virtual UCHAR* GetParsingBuffer() const;
		virtual int GetParsingBufferLength() const;
		virtual int GetCurrentPosition() const;
		virtual void SetCurrentPosition(int nPos);
		virtual int GetLineNumber() const;
		virtual int GetLineStartPosition() const;
		virtual bool IsEof() const;
		virtual UniString GetBaseURI() const;
		virtual int GetEntityStackLength() const;
		virtual int ParseNumericCharRef(REFUniStringBuilder* pInternalSubsetBuilder);
		virtual int ParseNamedCharRef(bool bExpand, REFUniStringBuilder* pInternalSubsetBuilder);
		virtual bool ParsePI(REFUniStringBuilder* sb);
		virtual bool ParseComment(REFUniStringBuilder* sb);
		virtual bool PushEntity(REFXMLSchemaEntity* pEntity, int nEntityId);
		virtual bool PopEntity(OUT REFXMLSchemaEntity*& pOldEntity, OUT int& nNewEntityId);
		virtual bool PushExternalSubset(const UniString& strSystemId, const UniString& strPublicId);

		virtual int ReadData();
		virtual void OnNewLine(int nPos);
		virtual void OnSystemId(const UniString& strSystemId, XMLLineInfo keywordLineInfo, XMLLineInfo systemLiteralLineInfo);
		virtual void OnPublicId(const UniString& strPublicId, XMLLineInfo keywordLineInfo, XMLLineInfo publicLiteralLineInfo);

		virtual XMLErrorContext GetLastError() const;
		virtual void SetLastError(XMLError nErrorCode);
		virtual void SetLastError(XMLError nErrorCode, const String& strErrorMsg);
		virtual void SetLastError(XMLError nErrorCode, int nPos);
		virtual void SetLastError(XMLError nErrorCode, const String& strErrorMsg, int nPos);
		virtual void SetLastError(XMLError nErrorCode, int nLineNo, int nLinePos);
		virtual void SetLastError(XMLError nErrorCode, const String& strErrorMsg, int nLineNo, int nLinePos);
	};

public:
	REFXMLTextReaderImpl(REFUniTextReader* pInput, REFNameTable* pNameTable);
	virtual ~REFXMLTextReaderImpl();

	//
	// Public properties
	//
	// Spefifies whether general entities should be automatically expanded or not
	XMLEntityHandling GetEntityHandling() const;
	void SetEntityHandling(XMLEntityHandling entityHandling);

	// Disables or enables support of W3C XML 1.0 Namespaces
	void SetSupportNamespaces(bool bSupportNamespaces);
	bool IsSupportNamespaces() const;

	bool IsNormalization() const;
	void SetNormalization(bool bNormalization);

	UniString GetEncoding() const;

	//
	// REFXMLReader override members
	//
	// Get the type of the current node.
	virtual XMLNodeType GetNodeType() const;
	// Gets the name of the current node, including the namespace prefix.
	virtual UniString GetName() const;

	// Gets the name of the current node without the namespace prefix.
	virtual UniString GetLocalName() const;
	// Gets the namespace URN (as defined in the W3C Namespace Specification) of the current namespace scope.
	virtual UniString GetNamespaceURI() const;
	// Gets the namespace prefix associated with the current node.
	virtual UniString GetPrefix() const;

	// Gets a value indicating whether
	virtual bool HasValue() const;
	// Gets the text value of the current node.
	virtual UniString GetValue() const;

	// Gets the base URI of the current node.
	virtual UniString GetBaseURI() const;
	// Gets a value indicating whether the current node is an empty element (for example, <MyElement/>).
	virtual bool IsEmptyElement() const;
	// Returns true of the current node is a default attribute declared in DTD.
	virtual bool IsDefault() const;

	// Gets the xml-nametable associated with the xmlreader.
	virtual REFNameTable* GetNameTable() const;

	// Moving through the stream, reads next node from the input data.
	// Returns true if the next node was read successfully; false if there are no more nodes to read.
	virtual bool Read();

	// Closes the stream, changes the ReadState to Closed, and sets all the properties back to zero/empty string.
	virtual void Close();

	// Returns the read state of the XmlReader.
	virtual ReadState GetReadState() const;

	// If on attribute, moves to the element that contains the attribute node
	virtual bool MoveToElement();
	// Moves to the first attribute of the current node
	virtual bool MoveToFirstAttribute();
	// Moves to the next attribute of the current node
	virtual bool MoveToNextAttribute();
	// Moves to an attribute at the specified index (position)
	virtual void MoveToAttribute(int i);
	// Moves to an attribute with the specified Name
	virtual bool MoveToAttribute(const UniString& strName);
	// Moves to an attribute with the specified LocalName and NamespceURI
	virtual bool MoveToAttribute(const UniString& strLocalName, const UniString& strNamespaceURI);
	// Iterates through the current attribute value's text and entity references chunks.
	virtual bool ReadAttributeValue();

	virtual const XMLErrorContext& GetLastError() const;
	virtual bool IsErrorOccurred() const;

// protected:
	virtual REFXMLSchemaInfo* GetDtdSchemaInfo() const;

protected:
	void SetLastError(XMLError nErrorCode);
	void SetLastError(XMLError nErrorCode, const String& strErrorMsg);
	void SetLastError(XMLError nErrorCode, int nPos);
	void SetLastError(XMLError nErrorCode, const String& strErrorMsg, int nPos);
	void SetLastError(XMLError nErrorCode, int nLineNo, int nLinePos);
	void SetLastError(XMLError nErrorCode, const String& strErrorMsg, int nLineNo, int nLinePos);

	void SetLastErrorTagMismatch(NodeData* pStartTag);

	//
	// Implementations
	//
protected:
	void InitVariables();
	void InitTextReaderInput(const UniString& strBaseUri, REFUniTextReader* pInput);
	void InitStringInput(const UniString& strBaseUri, const UniString& strOriginalEncoding, const UniString& str);

	//
	// Parse methods
	//
	// Parses the XML or text declaration and switched encoding if needed.
	bool ParseXmlDeclaration(bool bIsTextDecl);
	// Parses the document content
	bool ParseDocumentContent();
	// Parses element content
	bool ParseElementContent();
	// Parses the element end tag
	bool ParseEndElement();

	// Parses processing instruction
	bool ParsePI(REFUniStringBuilder* pPiInDtdStringBuilder = NULL);
	// Parses comment.
	bool ParseComment();
	bool ParseCData();
	// Parses CDATA section or comment
	bool ParseCDataOrComment(XMLNodeType type);
	// Parses a chunk of CDATA section or comment. Returns true when the end of CDATA or comment was reached.
	bool ParseCDataOrComment(XMLNodeType type, OUT int& nOutStartPos, OUT int& nOutEndPos);

	// Parses the element start tag
	bool ParseElement();
	UniString ParseUnexpectedToken(int nPos = -1);
	bool ParseRootLevelWhitespace();
	// Parses text or white space node.
	bool ParseText();
	// Reads the attributes
	bool ParseAttributes();

	// Parses DOCTYPE declaration
	bool ParseDoctypeDecl();

	// Parses a chunk of text starting at m_ps->nCharPos.
	bool ParseText(OUT int& nStartPos, OUT int& nEndPos, INOUT int& outOrChars);
	// When in ParsingStatePartialTextValue, this method parses and caches the rest of the value and stores it in m_pCurNode.
	bool FinishPartialValue();
	bool FinishOtherValueIterator();

	// Parses PI value
	bool ParsePIValue(OUT int& nOutStartPos, OUT int& nOutEndPos);

	bool ParseAttributeValueSlow(int nCurPos, UCHAR quoteChar, NodeData* pAttr);
	void AddAttributeChunkToList(NodeData* pAttr, NodeData* pChunk, INOUT NodeData* pLastChunk);

	bool ParseAttributeValueChunk();

	// Parse the name or qname. returns the end position, or -1 if error occurs.
	int ParseName();
	int ParseQName(OUT int& nColonPos);
	int ParseName(bool bIsQName, int iStartOffset, OUT int& nColonPos);

	bool ParseEntityReference();
	UniString ParseEntityName();
	// Parses numeric character entity reference (e.g. &#32; &#x20;).
	int ParseNumericCharRef(bool bExpand, REFUniStringBuilder* pInternalSubsetBuilder, OUT EntityType& entityType);
	// Parses named character entity reference (&amp; &apos; &lt; &gt; &quot;).
	int ParseNamedCharRef(bool bExpand, REFUniStringBuilder* pInternalSubsetBuilder);
	// Parses character entity reference (e.g. &#32; &#x20;&amp; &apos;).
	int ParseCharRefInline(int nStartPos, OUT int& nCharCount, OUT EntityType& entityType);
	// Parses numeric character entity reference (e.g. &#32; &#x20;).
	int ParseNumericCharRefInline(int nStartPos, bool bExpand, REFUniStringBuilder* pInternalSubsetBuilder, OUT int& nCharCount, OUT EntityType& entityType);
	// Parses named character entity reference (&amp; &apos; &lt; &gt; &quot;).
	int ParseNamedCharRefInline(int nStartPos, bool bExpand, REFUniStringBuilder* pInternalSubsetBuilder);

	EntityType HandleEntityReference(bool bIsInAttributeValue, EntityExpandType expandType, OUT int& nCharRefEndPos);
	// returns true == continue parsing
	// return false == unexpanded external entity, stop parsing and return
	EntityType HandleGeneralEntityReference(const UniString& strName, bool bIsInAttributeValue, bool bPushFakeEntityIfNullResolver, int nEntityStartLinePos);
	// return true if EndEntity node should be reported. The entity is stored in lastEntity.
	bool HandleEntityEnd(bool bCheckEntityNesting);

	//
	// Read methods.
	//
	// Reads more data to the character buffer, discarding already parsed chars / decoded bytes.
	int ReadData();
	void ShiftBuffer(int nSrcPos, int nDestPos, int nCount);

	int ReadDataInName(int nPos);
	int EatWhitespaces(REFUniStringBuilder* sb);

	//
	// NodeData helpers
	//
	NodeData* AddAttribute(int nEndNamePos, int nColonPos);
	NodeData* AddAttribute(const UniString& strLocalName, const UniString& strPrefix, const UniString& strNameWPrefix);
	NodeData* AddAttributeNoChecks(const UniString& strName, int nAttrDepth);
	NodeData* AddNode(int nNodeIndex, int nNodeDepth);

	void ResetAttributes();
	void FullAttributeCleanup();

	// Returns the whitespace node type according to the current whitespace handling setting and xml:space
	XMLNodeType GetWhitespaceType();
	XMLNodeType GetTextNodeType(int orChars);

	void OnNewLine(int nPos);
	void OnEof();
	void OnDefaultNamespaceDecl(NodeData* pAttr);
	void OnNamespaceDecl(NodeData* pAttr);
	void OnXmlReservedAttribute(NodeData* pAttr);

	void AddNamespace(const UniString& strPrefix, const UniString& strUri, NodeData* pAttr);

	// Returns NamespaceURI associated with the specified prefix in the current namespace scope.
	UniString LookupNamespace(const UniString strPrefix);
	UniString LookupNamespace(NodeData* pNode);

	void ElementNamespaceLookup();
	void AttributeNamespaceLookup();

	//
	// Attributes iteration.
	//
	bool IsInAttributeValueIterator();
	bool FinishAttributeValueIterator();
	int GetIndexOfAttributeWithoutPrefix(const UniString& strName);
	int GetIndexOfAttributeWithPrefix(const UniString& strName);

	// NOTE: The following methods only uses for with DTDs.
	void PushParsingState();
	void PopParsingState();
	bool IsInEntity();
	bool PushInternalEntity(REFXMLSchemaEntity* pEntity, int nEntityId);
	bool PopEntity();

protected:
	//
	// Helpers for DtdParserProxy
	//
	REFNameTable* DtdParserProxy_GetNameTable() const;
	UCHAR* DtdParserProxy_GetParsingBuffer() const;
	UniString DtdParserProxy_GetBaseURI() const;

	int DtdParserProxy_GetParsingBufferLength() const;
	int DtdParserProxy_GetCurrentPosition() const;
	void DtdParserProxy_SetCurrentPosition(int nPos);
	int DtdParserProxy_GetLineNumber() const;
	int DtdParserProxy_GetLineStartPosition() const;
	bool DtdParserProxy_IsEof() const;
	int DtdParserProxy_GetEntityStackLength() const;

	int DtdParserProxy_ParseNumericCharRef(REFUniStringBuilder* pInternalSubsetBuilder);
	int DtdParserProxy_ParseNamedCharRef(bool bExpand, REFUniStringBuilder* pInternalSubsetBuilder);
	bool DtdParserProxy_ParsePI(REFUniStringBuilder* sb);
	bool DtdParserProxy_ParseComment(REFUniStringBuilder* sb);
	bool DtdParserProxy_PushEntity(REFXMLSchemaEntity* pEntity, int nEntityId);
	bool DtdParserProxy_PopEntity(OUT REFXMLSchemaEntity*& pOldEntity, OUT int& nNewEntityId);
	bool DtdParserProxy_PushExternalSubset(const UniString& strSystemId, const UniString& strPublicId);

	int DtdParserProxy_ReadData();
	void DtdParserProxy_OnNewLine(int nPos);
	void DtdParserProxy_OnSystemId(const UniString& strSystemId, XMLLineInfo keywordLineInfo, XMLLineInfo systemLiteralLineInfo);
	void DtdParserProxy_OnPublicId(const UniString& strPublicId, XMLLineInfo keywordLineInfo, XMLLineInfo publicLiteralLineInfo);

private:
	//
	// Fields
	//
	bool		m_bV1Compat;
	XMLErrorContext		m_errorStatus;

	ParsingFunction		m_parsingFunction;
	ParsingFunction		m_nextParsingFunction;
	ParsingFunction		m_nextNextParsingFunction;

	// stack of parsing states (=stack of entities)
	REF<ParsingState>*	m_pParsingStateStack;
	int			m_nParsingStateStackLength;
	int			m_nParsingStateStackTop;
	ParsingState*	m_ps;

	// stack of nodes
	REF<NodeData>*	m_pNodes;
	int			m_nNodesLength;

	// current node & index
	NodeData*	m_pCurNode;
    int			m_nCurNodeIndex;
	REF<NodeData>	m_pNodeNull;

	// attributes info
	int			m_nCurAttrIndex;
	int			m_nAttrCount;
	bool		m_bAttrNeedNamespaceLookup;
	bool		m_bFullAttrCleanup;

	// ReadAttributeValue helpers
	int			m_nAttributeValueBaseEntityId;
	bool		m_bEmptyEntityInAttributeResolved;

	// current node base uri and encoding
	UniString	m_strReportedBaseUri;
	UniString	m_strReportedEncoding;

	// namespace handling
	REF<REFXMLNamespaceManager>	m_pNamespaceManager;
	UniString	m_strLastPrefix;

	// xml context (xml:space, xml:lang, default namespace)
	REF<XMLContext>		m_pXmlContext;

	// DTD
	REF<DtdParserProxy>	m_pDtdParserProxy;

	// fragment parsing
	XMLNodeType	m_fragmentType;

	// incremental read
	IncrementalReadState	m_incReadState;

	// misc
	REF<REFUniStringBuilder>	m_pStringBuilder;
	bool		m_bRootElementParsed;
	bool		m_bStandalone;
	int			m_nNextEntityId;
	ParsingMode	m_parsingMode;
	ReadState	m_readState;
	REFNameTable*	m_pNameTable;
	UniString	m_strXml;
	UniString	m_strXmlNs;
	int			m_nReadValueOffset;

	// settings
	bool		m_bNormalize;
	bool		m_bSupportNamespaces;
	bool		m_bIgnorePIs;
	bool		m_bIgnoreComments;
	XMLEntityHandling	m_entityHandling;
};

//////////////////////////////////////////////////////////////////////////////
// Inline methods

//
// ParsingState methods
//

inline REFXMLTextReaderImpl::ParsingState::ParsingState() :
	m_pChars(NULL),
	m_nCharsLength(0),
	m_nCharPos(0),
	m_nCharsUsed(0),
	m_bAppendMode(false),
	m_nLineNo(0),
	m_nLineStartPos(0),
	m_bIsEof(false),
	m_nEntityId(-1)
{
}
inline REFXMLTextReaderImpl::ParsingState::~ParsingState()
{
	if (m_pChars)
		delete[] m_pChars;
}
// Returns the current line position.
inline int REFXMLTextReaderImpl::ParsingState::GetLinePos() const
{
	return m_nCharPos - m_nLineStartPos;
}

//
// NodeData methods
//
inline int REFXMLTextReaderImpl::NodeData::GetLineNo() const
{
	return m_lineInfo.m_nLineNo;
}
inline int REFXMLTextReaderImpl::NodeData::GetLinePos() const
{
	return m_lineInfo.m_nLinePos;
}
inline REFXMLTextReaderImpl::NodeData::NodeData()
{
	Clear(XMLNodeType_None);
}
inline void REFXMLTextReaderImpl::NodeData::SetLineInfo(int nLineNo, int nLinePos)
{
	m_lineInfo.Set(nLineNo, nLinePos);
}
inline void REFXMLTextReaderImpl::NodeData::SetLineInfo2(int nLineNo, int nLinePos)
{
	m_lineInfo2.Set(nLineNo, nLinePos);
}
inline void REFXMLTextReaderImpl::NodeData::SetValueNode(XMLNodeType type, const UniString& strValue)
{
	m_type		= type;
	m_strValue	= strValue;

	m_strLocalName.SetEmpty();
	m_strPrefix.SetEmpty();
	m_strNameWPrefix.SetEmpty();
	m_strNs.SetEmpty();
}
inline void REFXMLTextReaderImpl::NodeData::SetNamedNode(XMLNodeType type, const UniString& strLocalName)
{
	SetNamedNode(type, strLocalName, UniString(), strLocalName);
}
inline void REFXMLTextReaderImpl::NodeData::SetNamedNode(XMLNodeType type, const UniString& strLocalName, const UniString& strPrefix,
	const UniString& strNameWPrefix)
{
	BFX_ASSERT( strLocalName.GetLength() > 0 );

	m_type = type;
	m_strLocalName = strLocalName;
	m_strPrefix = strPrefix;
	m_strNameWPrefix = strNameWPrefix;

	m_strNs.SetEmpty();
	m_strValue.SetEmpty();
}
inline void REFXMLTextReaderImpl::NodeData::SetValue(const UniString strValue)
{
	m_strValue = strValue;
}
inline bool REFXMLTextReaderImpl::NodeData::IsEmptyElement() const
{
	return m_type == XMLNodeType_Element && m_bIsEmptyOrDefault;
}
inline void REFXMLTextReaderImpl::NodeData::SetEmptyElement(bool bIsEmptyElement)
{
	BFX_ASSERT(m_type == XMLNodeType_Element);
	m_bIsEmptyOrDefault = bIsEmptyElement;
}
inline bool REFXMLTextReaderImpl::NodeData::IsDefaultAttribute() const
{
	return m_type == XMLNodeType_Attribute && m_bIsEmptyOrDefault;
}
inline void REFXMLTextReaderImpl::NodeData::SetDefaultAttribute(bool bIsDefaultAttribute)
{
	BFX_ASSERT(m_type == XMLNodeType_Attribute);
	m_bIsEmptyOrDefault = bIsDefaultAttribute;
}
inline void REFXMLTextReaderImpl::NodeData::CopyTo(REFUniStringBuilder* sb)
{
	CopyTo(0, sb);
}
inline void REFXMLTextReaderImpl::NodeData::CopyTo(int nValueOffset, REFUniStringBuilder* sb)
{
	if (nValueOffset <= 0)
		sb->Append(m_strValue);
	else
		sb->Append(m_strValue, nValueOffset, m_strValue.GetLength() - nValueOffset);
}
inline void REFXMLTextReaderImpl::NodeData::Clear(XMLNodeType type)
{
	m_type = type;
	m_bIsEmptyOrDefault = false;
	m_nEntityId = 0;
	m_pNextAttrValueChunk = NULL;

	m_lineInfo.Set(0, 0);
	m_lineInfo2.Set(0, 0);

	m_strLocalName.SetEmpty();
	m_strPrefix.SetEmpty();
	m_strNameWPrefix.SetEmpty();
	m_strNs.SetEmpty();
	m_strValue.SetEmpty();
}

inline bool REFXMLTextReaderImpl::IsInEntity()
{
	return (m_nParsingStateStackTop > 0);
}

inline REFXMLTextReaderImpl::XMLContext::XMLContext() :
	m_xmlSpace(XMLSpaceNone)
{
}
inline REFXMLTextReaderImpl::XMLContext::XMLContext(XMLContext* pPreviousContext)
{
	BFX_ASSERT(pPreviousContext != NULL);

	m_xmlSpace				= pPreviousContext->m_xmlSpace;
	m_strXmlLang			= pPreviousContext->m_strXmlLang;
	m_strDefaultNamespace	= pPreviousContext->m_strDefaultNamespace;
	m_pPreviousContext		= pPreviousContext->m_pPreviousContext;
}

//
// DtdParserProxy methods
//

// Constructors
inline REFXMLTextReaderImpl::DtdParserProxy::DtdParserProxy(REFXMLTextReaderImpl* pReader)
{
	BFX_ASSERT(pReader);
	m_pReader = pReader;
	m_pDtdParser = new REFXMLDtdParser(this);
}

inline void REFXMLTextReaderImpl::DtdParserProxy::Parse(bool bSaveInternalSubset)
{
	m_pDtdParser->Parse(bSaveInternalSubset);
}
inline REFXMLSchemaInfo* REFXMLTextReaderImpl::DtdParserProxy::GetDtdSchemaInfo() const
{
	return m_pDtdParser->GetSchemaInfo();
}
inline UniString REFXMLTextReaderImpl::DtdParserProxy::GetInternalDtdSubset() const
{
	BFX_ENSURE1(m_pDtdParser != NULL, "Invalid opOperation");
	return m_pDtdParser->GetInternalSubset();
}

//
// DtdParserAdapter proxies
//
inline REFNameTable* REFXMLTextReaderImpl::DtdParserProxy::GetNameTable() const
{
	return m_pReader->DtdParserProxy_GetNameTable();
}
inline UCHAR* REFXMLTextReaderImpl::DtdParserProxy::GetParsingBuffer() const
{
	return m_pReader->DtdParserProxy_GetParsingBuffer();
}
inline int REFXMLTextReaderImpl::DtdParserProxy::GetParsingBufferLength() const
{
	return m_pReader->DtdParserProxy_GetParsingBufferLength();
}
inline int REFXMLTextReaderImpl::DtdParserProxy::GetCurrentPosition() const
{
	return m_pReader->DtdParserProxy_GetCurrentPosition();
}
inline void REFXMLTextReaderImpl::DtdParserProxy::SetCurrentPosition(int nPos)
{
	m_pReader->DtdParserProxy_SetCurrentPosition(nPos);
}
inline int REFXMLTextReaderImpl::DtdParserProxy::GetLineNumber() const
{
	return m_pReader->DtdParserProxy_GetLineNumber();
}
inline int REFXMLTextReaderImpl::DtdParserProxy::GetLineStartPosition() const
{
	return m_pReader->DtdParserProxy_GetLineStartPosition();
}
inline bool REFXMLTextReaderImpl::DtdParserProxy::IsEof() const
{
	return m_pReader->DtdParserProxy_IsEof();
}
inline UniString REFXMLTextReaderImpl::DtdParserProxy::GetBaseURI() const
{
	return m_pReader->DtdParserProxy_GetBaseURI();
}
inline int REFXMLTextReaderImpl::DtdParserProxy::GetEntityStackLength() const
{
	return m_pReader->DtdParserProxy_GetEntityStackLength();
}
inline int REFXMLTextReaderImpl::DtdParserProxy::ParseNumericCharRef(REFUniStringBuilder* pInternalSubsetBuilder)
{
	return m_pReader->DtdParserProxy_ParseNumericCharRef(pInternalSubsetBuilder);
}
inline int REFXMLTextReaderImpl::DtdParserProxy::ParseNamedCharRef(bool bExpand, REFUniStringBuilder* pInternalSubsetBuilder)
{
	return m_pReader->DtdParserProxy_ParseNamedCharRef(bExpand, pInternalSubsetBuilder);
}
inline bool REFXMLTextReaderImpl::DtdParserProxy::ParsePI(REFUniStringBuilder* sb)
{
	return m_pReader->DtdParserProxy_ParsePI(sb);
}
inline bool REFXMLTextReaderImpl::DtdParserProxy::ParseComment(REFUniStringBuilder* sb)
{
	return m_pReader->DtdParserProxy_ParseComment(sb);
}
inline bool REFXMLTextReaderImpl::DtdParserProxy::PushEntity(REFXMLSchemaEntity* pEntity, int nEntityId)
{
	return m_pReader->DtdParserProxy_PushEntity(pEntity, nEntityId);
}
inline bool REFXMLTextReaderImpl::DtdParserProxy::PopEntity(OUT REFXMLSchemaEntity*& pOldEntity, OUT int& nNewEntityId)
{
	return m_pReader->DtdParserProxy_PopEntity(OUT pOldEntity, OUT nNewEntityId);
}
inline bool REFXMLTextReaderImpl::DtdParserProxy::PushExternalSubset(const UniString& strSystemId, const UniString& strPublicId)
{
	return m_pReader->DtdParserProxy_PushExternalSubset(strSystemId, strPublicId); 
}
inline int REFXMLTextReaderImpl::DtdParserProxy::ReadData()
{
	return m_pReader->DtdParserProxy_ReadData();
}
inline void REFXMLTextReaderImpl::DtdParserProxy::OnNewLine(int nPos)
{
	m_pReader->DtdParserProxy_OnNewLine(nPos);
}
inline void REFXMLTextReaderImpl::DtdParserProxy::OnSystemId(const UniString& strSystemId, XMLLineInfo keywordLineInfo, XMLLineInfo systemLiteralLineInfo)
{
	m_pReader->DtdParserProxy_OnSystemId(strSystemId, keywordLineInfo, systemLiteralLineInfo);
}
inline void REFXMLTextReaderImpl::DtdParserProxy::OnPublicId(const UniString& strPublicId, XMLLineInfo keywordLineInfo, XMLLineInfo publicLiteralLineInfo)
{
	m_pReader->DtdParserProxy_OnPublicId(strPublicId, keywordLineInfo, publicLiteralLineInfo);
}

inline XMLErrorContext REFXMLTextReaderImpl::DtdParserProxy::GetLastError() const
{
	return m_pReader->GetLastError();
}
inline void REFXMLTextReaderImpl::DtdParserProxy::SetLastError(XMLError nErrorCode)
{
	m_pReader->SetLastError(nErrorCode);
}
inline void REFXMLTextReaderImpl::DtdParserProxy::SetLastError(XMLError nErrorCode, const String& strErrorMsg)
{
	m_pReader->SetLastError(nErrorCode, strErrorMsg);
}
inline void REFXMLTextReaderImpl::DtdParserProxy::SetLastError(XMLError nErrorCode, int nPos)
{
	m_pReader->SetLastError(nErrorCode, nPos);
}
inline void REFXMLTextReaderImpl::DtdParserProxy::SetLastError(XMLError nErrorCode, const String& strErrorMsg, int nPos)
{
	m_pReader->SetLastError(nErrorCode, strErrorMsg, nPos);
}
inline void REFXMLTextReaderImpl::DtdParserProxy::SetLastError(XMLError nErrorCode, int nLineNo, int nLinePos)
{
	m_pReader->SetLastError(nErrorCode, nLineNo, nLinePos);
}
inline void REFXMLTextReaderImpl::DtdParserProxy::SetLastError(XMLError nErrorCode, const String& strErrorMsg, int nLineNo, int nLinePos)
{
	m_pReader->SetLastError(nErrorCode, strErrorMsg, nLineNo, nLinePos);
}

//
// Public properties
//
// Returns the current read state of the reader
inline ReadState REFXMLTextReaderImpl::GetReadState() const
{ 
	return m_readState;
}
inline bool REFXMLTextReaderImpl::IsNormalization() const
{
	BFX_ASSERT1(m_bV1Compat, "Normalization property cannot be accessed on v1Compat." );
	return m_bNormalize;
}
inline void REFXMLTextReaderImpl::SetNormalization(bool bNormalization)
{
	BFX_ASSERT1(m_bV1Compat, "Normalization property cannot be changed on v1Compat." );
	BFX_ENSURE(m_readState != ReadState_Closed);	// InvalidOperationException
	m_bNormalize = bNormalization;
	// TODO: More...
}
inline UniString REFXMLTextReaderImpl::GetEncoding() const
{
	return (m_readState == ReadState_Interactive) ? m_strReportedEncoding : UniString();
}

//
// Helpers for DtdParserProxy
//

inline REFNameTable* REFXMLTextReaderImpl::DtdParserProxy_GetNameTable() const
{
	return m_pNameTable;
}
inline UCHAR* REFXMLTextReaderImpl::DtdParserProxy_GetParsingBuffer() const
{
	return m_ps->m_pChars;
}
inline int REFXMLTextReaderImpl::DtdParserProxy_GetParsingBufferLength() const
{
	return m_ps->m_nCharsUsed;
}
inline int REFXMLTextReaderImpl::DtdParserProxy_GetCurrentPosition() const
{
	return m_ps->m_nCharPos;
}
inline void REFXMLTextReaderImpl::DtdParserProxy_SetCurrentPosition(int nPos)
{
	BFX_ASSERT(nPos >= 0 && nPos <= m_ps->m_nCharsUsed);
	m_ps->m_nCharPos = nPos;
}
inline int REFXMLTextReaderImpl::DtdParserProxy_GetLineNumber() const
{
	return m_ps->m_nLineNo;
}
inline int REFXMLTextReaderImpl::DtdParserProxy_GetLineStartPosition() const
{
	return m_ps->m_nLineStartPos;
}
inline bool REFXMLTextReaderImpl::DtdParserProxy_IsEof() const
{
	return m_ps->m_bIsEof;
}
inline UniString REFXMLTextReaderImpl::DtdParserProxy_GetBaseURI() const
{
	// TODO: resolve uri
	return m_ps->m_strBaseUri;
}
inline int REFXMLTextReaderImpl::DtdParserProxy_GetEntityStackLength() const
{
	return m_nParsingStateStackTop + 1;
}
inline int REFXMLTextReaderImpl::DtdParserProxy_ParseNumericCharRef(REFUniStringBuilder* pInternalSubsetBuilder)
{
	EntityType entType;
	return ParseNumericCharRef(true, pInternalSubsetBuilder, OUT entType);
}
inline int REFXMLTextReaderImpl::DtdParserProxy_ParseNamedCharRef(bool bExpand, REFUniStringBuilder* pInternalSubsetBuilder)
{
	return ParseNamedCharRef(bExpand, pInternalSubsetBuilder);
}
inline bool REFXMLTextReaderImpl::DtdParserProxy_ParsePI(REFUniStringBuilder* sb)
{
	bool bResult;
	if (sb == NULL)
	{
		ParsingMode pm = m_parsingMode;
		m_parsingMode = ParsingModeSkipNode;
		bResult = ParsePI(NULL);
		m_parsingMode = pm;
	}
	else
	{
		bResult = ParsePI(sb);
	}
	return bResult;
}
inline bool REFXMLTextReaderImpl::DtdParserProxy_ParseComment(REFUniStringBuilder* sb)
{
	BFX_ASSERT(m_parsingMode == ParsingModeFull);

	bool bResult;
	if (sb == NULL)
	{
		ParsingMode savedParsingMode = m_parsingMode;
		m_parsingMode = ParsingModeSkipNode;
		bResult = ParseCDataOrComment(XMLNodeType_Comment);
		m_parsingMode = savedParsingMode;
	}
	else
	{
		NodeData* pOriginalCurNode = m_pCurNode;
		m_pCurNode = AddNode(m_nCurNodeIndex + m_nAttrCount + 1, m_nCurNodeIndex);
		bResult = ParseCDataOrComment(XMLNodeType_Comment);
		if (bResult)
			m_pCurNode->CopyTo(sb);
		m_pCurNode = pOriginalCurNode;
	}
	return bResult;
}
inline bool REFXMLTextReaderImpl::DtdParserProxy_PushEntity(REFXMLSchemaEntity* pEntity, int nEntityId)
{
	if (pEntity->IsExternal())
	{
		BFX_ASSERT(false);
		return false;
	}
	else
	{
		PushInternalEntity(pEntity, nEntityId);
		return false;
	}
}
inline bool REFXMLTextReaderImpl::DtdParserProxy_PopEntity(OUT REFXMLSchemaEntity*& pOldEntity, OUT int& nNewEntityId)
{
	if (m_nParsingStateStackTop == 0)
	{
		pOldEntity = NULL;
		nNewEntityId = -1;
		return false;
	}
	pOldEntity = m_ps->m_pEntity;
	PopEntity();
	nNewEntityId = m_ps->m_nEntityId;
	return true;
}
inline bool REFXMLTextReaderImpl::DtdParserProxy_PushExternalSubset(const UniString& strSystemId, const UniString& strPublicId)
{
	BFX_ASSERT(m_nParsingStateStackTop == 0 );
	BFX_ASSERT(strSystemId.GetLength() > 0 || strPublicId.GetLength() > 0);

	// TODO: xxx
	return false;
}
inline int REFXMLTextReaderImpl::DtdParserProxy_ReadData()
{
	return ReadData();
}
inline void REFXMLTextReaderImpl::DtdParserProxy_OnNewLine(int nPos)
{
	OnNewLine(nPos);
}
inline void REFXMLTextReaderImpl::DtdParserProxy_OnSystemId(const UniString& strSystemId, XMLLineInfo keywordLineInfo, XMLLineInfo systemLiteralLineInfo)
{
	NodeData* pAttr = AddAttributeNoChecks(USTR("SYSTEM"), m_nCurNodeIndex); 
	pAttr->SetValue(strSystemId);
	pAttr->m_lineInfo = keywordLineInfo;
	pAttr->m_lineInfo2 = systemLiteralLineInfo;
}
inline void REFXMLTextReaderImpl::DtdParserProxy_OnPublicId(const UniString& strPublicId, XMLLineInfo keywordLineInfo, XMLLineInfo publicLiteralLineInfo)
{
	NodeData* pAttr = AddAttributeNoChecks(USTR("PUBLIC"), m_nCurNodeIndex);
	pAttr->SetValue(strPublicId);
	pAttr->m_lineInfo = keywordLineInfo;
	pAttr->m_lineInfo2 = publicLiteralLineInfo;
}

}	//	namespace BFX

#endif	//	__BFX_REFXMLTEXTREADERIMPL_H__
